Curso de ScriptVox Intermedirio - Aula 3 - Prof. Oswaldo Vernet - iNCE/UFRJ



Na aula passada, utilizamos algumas funes internas do Scriptvox, como RAND, POS

e PALAVRA. O objetivo desta terceira aula  aprender a construir nossas prprias funes.



Vimos que uma chamada de funo se comporta tanto como operador quanto como operando durante

a avaliao de uma expresso. As informaes que passamos para a funo para que

ela realiza seu processamento so chamadas de parmetros. O valor que a funo retorna  chamado

valor de retorno. Este valor  usado como operando na avaliao da expresso 

onde a chamada da funo aparece.



Nesta aula, vamos aprender a criar nossas prprias funes. Como de hbito, vamos

partir de um problema concreto a ser resolvido.



Suponhamos que, em diversos pontos de um script, precisamos fazer uma pergunta ao

usurio. A pergunta pode variar, dependendo do lugar em que  feita. A ideia

 que a pergunta seja escrita na tela, seguida de uma interrogao, e que o usurio 

digite uma resposta, que ser uma tecla lida sem eco. Esta tecla poder ser "S" (resposta sim),

"N" (resposta no), ou "R" (o usurio pede que a pergunta seja repetida).

Qualquer tecla diferente destas trs deve ser ignorada e, neste caso, uma outra

tecla deve ser aguardada. O usurio tem, no mximo, trs chances de errar.

Aps isso, ele deve ser insultado e a resposta "no" ser assumida.



Se a resposta final for "sim", a varivel "resposta" dever armazenar o inteiro 1

(que vai significar "SIM"); se a resposta for "no", a "varivel" resposta dever

armazenar o inteiro 0 (que vai significar "NO"). Portanto, quem chama a funo,

deve saber que o retorno 1 significa sim e o retorno 0 significa no.



Com o que conhecemos at agora de ScriptVox, poderamos rascunhar esta ideia da

seguinte maneira (lembre-se que tudo o que vem aps um par de barras  comentrio):



pergunta := "Voc deseja continuar"             // pergunta pura, sem a interrogao no fim



@inicio

chances := 0

escreve pergunta "?"                            // na hora de escrever  que colocamos a interrogao



@leitura

chances := chances + 1

se chances > 3                                  // se chances for maior que trs, o usurio j errou o quanto podia

escreve 

escreve "Sua besta, era pra teclar S, N ou R."  // acrescente aqui os xingamentos que voc quiser

resposta := 0                                   // assume a resposta "no", que  zero para ns

desvia @fim                                     // desvia para o final

fim se

 

escreve "Tecle S, N ou R: " &

l tecla &                                      // L a tecla, sem ecoar

se tecla = "S"                                  // Lida a tecla, temos que ver o que o usurio digitou

resposta := 1

seno

se tecla = "s"

resposta := 1

seno

se tecla = "N"

resposta := 0

seno

se tecla = "n"

resposta := 0

seno

se tecla = "R" 

desvia @inicio                                  // o usurio pediu para repetir; volta l pro incio

seno

se tecla = "r"

desvia @inicio

seno

desvia @leitura                                 // a tecla no  nenhuma das esperadas; volta a ler uma tecla

fim se

@fim



* Aqui apenas conferimos a resposta

se resposta = 0                                 // Decodifica a resposta, conforme seja 0 ou 1

escreve "A resposta  NO"

seno

escreve "A resposta  SIM"

fim se





O funcionamento  simples e dispensa maiores explicaes. Teste no interpretador e veja 

se est funcionando.



Antes de transformarmos este trecho de script numa funo, vamos melhor-lo um pouco.



Primeiramente, os testes duplos incomodam: testar se tecla  igual a "S" (maisculo) 

e, caso no seja, testar em seguida se tecla  igual a "s" (minsculo)  trabalho demais. 

Na verso 6.0, introduzimos uma novidade no comando "L": o modificador MAIUSC, que j converte 

a cadeia lida para maisculas. Utilizando este modificador, nosso trecho se simplifica e

fica assim:



pergunta := "Voc deseja continuar"



@inicio

chances := 0

escreve pergunta "?"



@leitura

chances := chances + 1

se chances > 3

escreve 

escreve "Sua besta, era pra teclar S, N ou R."

resposta := 0 

desvia @fim

fim se

 

escreve "Tecle S, N ou R: " &

l MAIUSC tecla &

se tecla = "S"

resposta := 1

seno

se tecla = "N"

resposta := 0

seno

se tecla = "R" 

desvia @inicio

seno

desvia @leitura

fim se

@fim



* Aqui a resposta  usada

se resposta = 0

escreve "A resposta  NO"

seno

escreve "A resposta  SIM"

fim se





Teste este pequeno script no interpretador e veja se continua funcionando.



Agora sim, vamos transformar o cdigo em uma funo. Primeiramente precisamos dar um nome

para a funo e pensar como ela ser usada no script. J que a funo faz uma pergunta,

vamos cham-la de FazPergunta. Mas qual pergunta dever ser feita?  J que a 

funo poder ser utilizada em diversos pontos diferentes do script,  razovel supor

que a pergunta ir variar de acordo com o que queremos perguntar ao usurio em cada ponto

do script. Portanto, a pergunta a ser feita ser um parmetro para a funo, 

ou seja, a funo receber como parmetro uma cadeia de caracteres contendo a pergunta. 

Portanto, uma maneira de usar a funo seria a seguinte:



resposta := FazPergunta ("Deseja continuar")

se resposta = 1

* o usurio deseja continuar

seno

* o usurio no deseja continuar

fim se



Ou, mais resumidamente, podemos at eliminar a varivel "resposta", usando diretamente

na comparao o valor retornado pela funo. Assim:



se FazPergunta ("Deseja continuar") = 1

* o usurio deseja continuar

seno

* o usurio no deseja continuar

fim se



Muito bem. J sabemos exatamente como usar a funao; falta, agora, cri-la. Para isto, 

usaremos o comando FUNO, que  uma novidade da verso 6. De modo semelhante a outros 

comandos, ele agrega linhas em um bloco, que deve ser terminado pelo comando FIM FUNO.

Assim:



funo FazPergunta

*

* Aqui vem o BLOCO da funo

*

fim funo



Indicamos que a funo receber um parmetro colocando entre parnteses, logo aps

o nome da funo, o nome de uma varivel que receber o parmetro no momento da chamada.

Assim:



funo FazPergunta (pergunta)

*

* Aqui vem o BLOCO da funo

*

fim funo



Como o ScriptVox interpreta estas linhas?  Ao se deparar com o comando FUNO, ele entende

que, at aparecer o comando FIM FUNO, estaremos definindo uma funo nossa, que ns

programamos. O nome da funo, atravs do qual ela ser chamada em expresses, aparece 

logo depois do comando FUNO. No exemplo, a funo se chama FazPergunta.



Em seguida, o Scriptvox procura, na mesma linha do comando FUNO, se existem nomes de

variveis entre parnteses. Se existirem, significa que a funo receber parmetros e que

os valores destes parmetros estaro armazenados nas variveis que aparecerem entre parnteses.

No nosso caso, a funo recebe apenas um parmetro e precisamos apenas da varivel "pergunta".



Agora sim, podemos encaixar no bloco da funo FazPergunta os comandos que rascunhamos no

incio da aula:



* Aqui comea a funo FazPergunta

funo FazPergunta (pergunta)

@inicio

chances := 0

escreve pergunta "?"          // Aqui usamos o valor da varivel "pergunta", que  um parmetro



@leitura

chances := chances + 1

se chances > 3

escreve 

escreve "Sua besta, era pra teclar S, N ou R."

resposta := 0 

desvia @fim

fim se

 

escreve "Tecle S, N ou R: " &

l MAIUSC tecla &

se tecla = "S"

resposta := 1

seno

se tecla = "N"

resposta := 0

seno

se tecla = "R" 

desvia @inicio

seno

desvia @leitura

fim se

@fim

fim funo

* Aqui termina a funo FazPergunta



Estamos quase l. Faltam ainda alguns detalhes. O combinado  que a funo retorne 0 ou 1,

dependendo do que o usurio teclou. Mas ela no est fazendo isso. O que ela est fazendo 

 armazenar na varivel "resposta" o valor de retorno. Como fazemos, ento, para que a funo 

retorne o valor, em vez de armazen-lo em uma varivel?   simples: usando o comando RETORNA, 

que j existia nas verses anteriores do ScriptVox. S que, agora, o comando RETORNA deve 

especificar o valor que ser retornado. Nossa funo, quase pronta, ficar assim:



* Aqui comea a funo FazPergunta

funo FazPergunta (pergunta)

@inicio

chances := 0

escreve pergunta "?"



@leitura

chances := chances + 1

se chances > 3

escreve 

escreve "Sua besta, era pra teclar S, N ou R."

retorna 0 

fim se

 

escreve "Tecle S, N ou R: " &

l MAIUSC tecla &

se tecla = "S"

retorna 1

seno

se tecla = "N"

retorna 0

seno

se tecla = "R" 

desvia @inicio

seno

desvia @leitura

fim se

fim funo

* Aqui termina a funo FazPergunta



Observou que o rtulo @fim e o comando Desvia @fim desapareceram? Para que eles serviam,

na verso original?  Serviam para causar um desvio para o final do processamento, caso o

nmero de chances se esgotasse. O comando RETORNA j faz isso: retornar de uma funo

significa encerrar as atividades desta funo, disponibilizando a quem chamou

o valor de retorno. Ento, no precisamos mais daquele Desvia @fim que havia antes.



Experimente, ento, executar o seguinte script no novo interpretador:



se FazPergunta ("Voc  homem") = 1

escreve "O usurio  homem"

seno

escreve "O usurio  mulher"

fim se



se FazPergunta ("Voc  maior de idade") = 1

escreve "O usurio  maior de idade"

seno

escreve "O usurio  menor de idade"

fim se



termina



*  Aqui comea a funo FazPergunta

funo FazPergunta (pergunta)

@inicio

chances := 0

escreve pergunta "?"

@leitura

chances := chances + 1

se chances > 3

escreve 

escreve "Sua besta, era pra teclar S, N ou R."

retorna 0 

fim se

escreve "Tecle S, N ou R: " &

l MAIUSC tecla &

se tecla = "S"

retorna 1

seno

se tecla = "N"

retorna 0

seno

se tecla = "R" 

desvia @inicio

seno

desvia @leitura

fim se

fim funo

* Fim da funo FazPergunta



Repare que a funo FazPergunta  usada em duas linhas diferentes do script antes mesmo 

de ser definida. Esta ordem  irrelevante. Alguns programadores preferem

colocar todas as suas funes no incio do script e o cdigo principal depois delas.

No ScriptVox verso 6.0, tanto faz: voc pode escolher qual estilo mais lhe agrada.



Vamos, agora, acrescentar mais um detalhe muito importante  nossa funo FazPergunta.

Voc observou quantas e quais so as variveis que esta funo usa, alm da varivel 

"pergunta", que armazena o parmetro para a funo?  Examine o cdigo e conte quantas so.



So duas variveis: "chances" e "tecla", correto? Observe que estas duas variveis

s so necessrias enquanto a funo FazPergunta est sendo executada. Quando a funo

termina, no interessa para quem chamou quais so os valores armazenados nelas. O

que interessa  o valor 0 ou 1 retornado.



Quando isto acontece com alguma varivel, devemos informar ao ScriptVox que ela 

LOCAL  funo. Variveis locais so criadas sempre que uma funo  chamada e so

destrudas quando a funo retorna.



Para dizer quais variveis so locais, basta colocar, na linha do comando FUNO, 

depois do fecha parnteses que finaliza a lista de parmetros, o caractere dois

pontos ":" seguido dos nomes das variveis que queremos tornar locais  funo,

separados por vrgulas. No nosso exemplo, ento, a funo FazPergunta ficaria assim:



* Aqui comea a funo FazPergunta

funo FazPergunta (pergunta) : chances, tecla

@inicio

chances := 0

escreve pergunta "?"

@leitura

chances := chances + 1

se chances > 3

escreve 

escreve "Sua besta, era pra teclar S, N ou R."

retorna 0 

fim se

escreve "Tecle S, N ou R: " &

l MAIUSC tecla &

se tecla = "S"

retorna 1

seno

se tecla = "N"

retorna 0

seno

se tecla = "R" 

desvia @inicio

seno

desvia @leitura

fim se

fim funo

* Fim da funo FazPergunta



A linha:



funo FazPergunta (pergunta) : chances, tecla



 denominada CABEALHO da funo. O Scriptvox, quando se depara com este cabealho,

entende que ali comea a definio da funo FazPergunta Ele entende tambm que 

esta funo espera um nico parmetro, cujo valor ser atribudo  varivel "pergunta" 

no momento em que a funo for chamada. Por fim, ele saber que as variveis "chance" 

e "tela" so locais  funo FazPergunta, isto , elas s vo existir enquanto FazPergunta 

estiver sendo executada.



Voc deve estar se perguntando: e o que acontece se no informarmos ao Scriptvox

que estas variveis so locais? Muito simples: elas sero consideradas variveis 

GLOBAIS, como todas as outras. Isto significa que, quando a funo FazPergunta retornar,

elas estaro l, armazenando os ltimos valores que foram atribudos a elas.

Muitas vezes,  isso que queremos: ter acesso s variveis usadas pela funo

mesmo quando a funo j terminou; mas outras vezes, no.



Sempre que voc for programar uma funo, identifique cuidadosamente quais as variveis 

que devem sobreviver aps o trmino da funo e quais delas s interessam enquanto 

a funo estiver executando. Estas ltimas devem ser declaradas como LOCAIS.



S para encurtar um pouco mais o nosso exemplo, a funo FazPergunta ainda pode

ser mais otimizada. Veja a seguir:



* Aqui comea a funo FazPergunta

funo FazPergunta (pergunta) : chances, tecla

@inicio

chances := 0

escreve pergunta "?"

@leitura

chances := chances + 1

se chances > 3

escreve 

escreve "Sua besta, era pra teclar S, N ou R."

retorna 0 

fim se

escreve "Tecle S, N ou R: " &

l MAIUSC tecla &

se tecla = "S" retorna 1

se tecla = "N" retorna 0

se tecla = "R" desvia @inicio

desvia @leitura

fim funo

* Fim da funo FazPergunta



Observou que no precisamos dos comandos SENO que apareciam antes? Trocamos tudo

por comandos SE de uma linha. Agora sim, podemos dizer que nossa funo est pronta,

o que no significa que voc no deva tentar melhor-la ainda mais!



Mesmo sem esta novidade das funes, nas verses anteriores do ScriptVox j era

possvel fazer algo semelhante com o comando "CHAMA". Lembra-se dele?  Pois, neste

curso, o comando CHAMA deve ser abandonado e as funes devem ser utilizadas

em seu lugar.



Para fixarmos bem o que acontece quando uma funo  chamada, faamos uma outra

analogia com a vida diria. Imagine que voc est estudando e, de repente, aparece

em um texto uma palavra cujo significado voc desconhece. Se voc  um aluno

aplicado e quer aprender, o que voc faz?  Interrompe momentaneamente a leitura do

texto, anota a palavra num pedacinho de papel, pega o dicionrio, procura a palavra 

desconhecida, l a explicao, compreende o seu significado e retorna ao texto, 

agora com a palavra esclarecida. Uma chamada de funo funciona exatamente assim. 

No caso, o parmetro  a palavra que foi anotada no pedacinho de papel e o valor de

retorno  o significado que est no dicionrio. A funo, na verdade,  a busca

que voc faz, por ordem alfabtica, folheando as pginas at encontrar a palavra.



Podem existir funes que no precisam de parmetros para funcionar. Um exemplo

bem comum seria reunir em uma funo todo aquele procedimento de boas vindas que

costumamos colocar no incio de alguns scripts. Assim:



funo BemVindo ()

escreve "Ol. Digite seu nome: " &

L nome

escreve "Seja bem vindo, " nome ". Hoje  " dia () ", dia " data () " e so " hora () "."

fim funo



Observe que esta funo no recebe parmetros e nem retorna valores. Esquisita ela, no?

Na verdade, ela termina suas atividades quando o comando "FIM FUNO"  atingido,

j que no existe nenhum comando "RETORNA".



Reparou que ela usa a varivel "nome"?  Ela  local ou global?  Se for local, ela

desaparecer quando a funo terminar. Se for global, teremos acesso ao valor armazenado

nela mesmo depois do trmino da funo. Experimente, ento, o seguinte script no

interpretador:



BemVindo()            // Aqui a funo BemVindo  chamada

escreve "O nome que voc digitou foi " nome 



funo BemVindo ()    // Aqui a funo BemVindo  definida

escreve "Ol. Digite seu nome: " &

L nome

escreve "Seja bem vindo, " nome ". Hoje  " dia () ", dia " data () " e so " hora () "."

fim funo



Aps as boas vindas, aparecer escrita na tela a frase "O nome que voc digitou foi X",

imaginando que voc tenha digitado X quando a pergunta apareceu. Logo, a varivel "nome"

 global: ela  inicializada dentro da funo BemVindo, pelo comando "L", mas seu valor

continua acessvel aps a funo BemVindo terminar.



Agora modifique e execute o script declarando a varivel "nome" como local  funo BemVindo.

Assim:



BemVindo()                           // Aqui a funo BemVindo  chamada

escreve "O nome que voc digitou foi " nome 



funo BemVindo () : nome            // Aqui a funo BemVindo  chamada

escreve "Ol. Digite seu nome: " &

L nome

escreve "Seja bem vindo, " nome ". Hoje  " dia () ", dia " data () " e so " hora () "."

fim funo



Observou o que aconteceu? O ScriptVox reclamou que a varivel "nome" no foi inicializada

e a frase que aparecer na tela ser a seguinte: "O nome que voc digitou foi invlido".

Voc consegue deduzir o que houve?  simples: a varivel "nome" que a funo BemVindo

utilizou era local e desapareceu quando a funo terminou. Da, o interpretador prossegue

a execuo na linha seguinte quela onde a funo BemVindo foi chamada. Nesta linha,

mandamos escrever 



"O nome que voc digitou foi " nome



S que esta varivel "nome"  global, no  a mesma usada pela funo BemVindo!

E esta varivel nunca foi inicializada antes e, por isso, o ScriptVox protesta.



Experimente mais uma modificao:



nome := "Joo Ningum"           // Inicializa a varivel global "nome" com a cadeia "Joo Ningum"

BemVindo()

escreve "O nome que voc digitou foi " nome 



funo BemVindo () : nome

escreve "Ol. Digite seu nome: "

L nome

escreve "Seja bem vindo, " nome ". Hoje  " dia () ", dia " data () " e so " hora () "."

fim funo



Notou a mudana?



Moral da Histria. Podemos ter uma varivel global e uma varivel local a alguma

funo com o mesmo nome. O valor de uma no interfere no valor da outra.



Voc tambm deve ter reparado no comando "Escreve", dentro do BLOCO da funo BemVindo.

H trs chamadas de funes neste comando, percebeu?  Isto fica bem claro quando colocamos

o abre e fecha parnteses aps os nomes das funes "dia", "data" e "hora".

 

Para finalizar, vamos convencionar algumas regras para usar funes ao longo deste curso.



Primeiramente, sempre que chamarmos uma funo, mesmo que ela no tenha parmetros, vamos

colocar o abre e fecha parnteses depois do nome da funo. Assim, fica bem claro que se

trata de uma chamada de funo e no de uma varivel comum.



Alm disso, quando definimos uma funo com o comando FUNO, mesmo que ela no receba

parmetros, ainda assim vamos colocar o abre e fecha parnteses aps seu nome, para ficar

coerente com a maneira de chamar a funo.



Se a funo necessitar receber mais de um parmetro, devemos separar os nomes dos parmetros

por vrgulas, dentro do abre e fecha parnteses.



Se a funo utilizar variveis locais, os nomes destas varivel devem aparecer separados

por vrgulas logo depois do caractere dois pontos ":" que colocamos aps o fecha parnteses

da lista de parmetros. 





EXERCCIOS



Perguntas de Estudo Dirigido:



1)  H alguma diferena entre a chamada de uma funo interna do ScriptVox e a chamada de uma

    funo criada pelo programador e definida no script?  Se houver, qual  ela?

2)  Como se define uma funo num Script?  Qual o comando utilizado e como ele deve ser usado?

3)  Como se declaram os parmetros na definio de uma funo?

4)  O que  uma variveis LOCAL e qual a principal diferena entre uma varivel LOCAL e uma varivel

    GLOBAL?

5)  Uma varivel LOCAL pode ter o mesmo nome de uma varivel GLOBAL?  H confuso nos valores que

    elas armazenam?

6)  Como fazemos para uma funo retornar um determinado valor?

7)  Como funciona o comando RETORNA?  

8)  Quais so as duas maneiras de uma funo terminar sua execuo?

9)  Quando uma funo termina de executar, onde prossegue o fluxo de execuo?  Ou seja, em que ponto

    do script o ScriptVox continua a execuo?

10) O que  o cabealho de uma funo?

11) Faz alguma diferena definir uma funo antes de us-la ou definir a funo depois de us-la?





Exerccio de Avaliao (envie at meio-dia de 26 de janeiro para scriptvox@gmail.com):



Sua tarefa, desta vez, ser implementar um script de questionrio. Ele funciona assim:

no incio, voc d as boas vindas ao usurio, pergunta seu nome, fala gentilezas, etc... 

Depois, pergunta tambm o nome do arquivo contendo as perguntas do questionrio.

Cada pergunta deve ocupar apenas uma linha do arquivo.



Cada pergunta lida do arquivo dever ser escrita na tela e o script dever aguardar que o usurio responda.

As respostas do usurio devero ser guardadas em um arquivo cujo nome  o nome do usurio seguido

da extenso ".resp". Assim, se o usurio se chama Guto, o arquivo com as respostas ser

"Guto.resp".



O importante  trabalhar com funes neste script. Portanto, as boas vindas devem ser dadas

em uma funo, que deve retornar o nome do usurio que foi perguntado. A leitura de cada pergunta, 

sua escrita na tela, a espera pela resposta, a leitura da resposta e sua escrita no arquivo

devero ser feitos em outra funo. Esta funo dever retornar o nmero de perguntas feitas.

Por fim, o script deve informar quantas perguntas foram feitas ao usurio.



Se quiser, invente mais funes. Mas essas duas que citamos so obrigatrias: uma que d as boas

vindas e outra que processa as perguntas e as respostas.



Pense com calma quais sero os parmetros, quais sero os valores retornados e quais sero 

as variveis locais e globais.



Seu script deve ser testado com as perguntas do estudo dirigido (copie-as para o arquivo que ser

lido pelo script, colocando uma em cada linha, sem quebrar).



Lembre-se que a extenso a partir de agora  ".PRO", para o nome do script.



Bom estudo!



Oswaldo Vernet















